﻿using System.Collections.Generic;
using NHibernate;
using NHibernate.Context;

namespace Ornament.NHibernates
{
    public class SessionManager
    {
        private static readonly Dictionary<string, NhConfigFileInfo> Files = new Dictionary<string, NhConfigFileInfo>();

        private static readonly SortedDictionary<string, SessionManager> Inner =
            new SortedDictionary<string, SessionManager>();

        private static readonly string DefaultSessionKey;
        private readonly NhConfigFileInfo _configInfo;

        static SessionManager()
        {
            InitFiles();
            foreach (string sessionName in Files.Keys)
            {
                if (DefaultSessionKey == null || DefaultSessionKey == "default")
                    DefaultSessionKey = sessionName;
                Inner.Add(sessionName, new SessionManager(sessionName));
            }
        }

        private SessionManager(string sessionFactoryName)
        {
            if (!Files.ContainsKey(sessionFactoryName))
                throw new OrnamentConfigurationException("Can't find the session-factory named " + sessionFactoryName);
            _configInfo = Files[sessionFactoryName];
        }

        /// <summary>
        /// Gets session manager instance;
        /// </summary>
        public static SessionManager Instance
        {
            get { return Inner[DefaultSessionKey]; }
        }


        /// <summary>
        /// Gets Session after use <see cref="IniSession"/>
        /// </summary>
        public ISession CurrentSession
        {
            get { return GetSessionFactory().GetCurrentSession(); }
        }

        /// <summary>
        /// 需要自己handler session
        /// </summary>
        public ISession NewSession
        {
            get { return GetSessionFactory().OpenSession(); }
        }

        /// <summary>
        /// 這個也要自己Handler
        /// </summary>
        public IStatelessSession Sessionless
        {
            get { return GetSessionFactory().OpenStatelessSession(); }
        }

        public NhConfigFileInfo Config
        {
            get { return _configInfo; }
        }

        public static SessionManager GetInstance(string sessionFactoryName)
        {
            if (!Inner.ContainsKey(sessionFactoryName))
                throw new OrnamentConfigurationException("Can't find the session-factory named " + sessionFactoryName);
            return Inner[sessionFactoryName];
        }

        private static void InitFiles()
        {
            foreach (NhConfigFileInfo fileinfo in NhConfigFileInfo.GetNHFileInfos())
            {
                if (Files.ContainsKey(fileinfo.SessionFactoryName))
                {
                    throw new OrnamentConfigurationException(fileinfo.SessionFactoryName +
                                                             "is duplicate. please check the nh config file to make sure session-factory's name is unique ");
                }
                Files.Add(fileinfo.SessionFactoryName, fileinfo);
            }
        }

        public ISessionFactory GetSessionFactory()
        {
            return _configInfo.SessionFactory;
        }

        public void CleanUp()
        {
            if (CurrentSessionContext.HasBind(GetSessionFactory()))
            {
                ISession currentSession = GetSessionFactory().GetCurrentSession();

                if (currentSession.Transaction != null && currentSession.Transaction.IsActive)
                {
                    currentSession.Transaction.Commit();
                }
                currentSession.Flush();
                currentSession.Close();
                CurrentSessionContext.Unbind(GetSessionFactory());
            }
        }

        public void IniSession()
        {
            if (!CurrentSessionContext.HasBind(GetSessionFactory()))
            {
                ISession session = GetSessionFactory().OpenSession();
                CurrentSessionContext.Bind(session);
            }
        }

        public static void CleanAll()
        {
            foreach (SessionManager a in Inner.Values)
            {
                a.CleanUp();
            }
        }
    }
}